/*
 * This file (MathOperator.java) is protected by the GNU GPL licence (v2). 
 * Please read the license.txt attached for further informations. 
 * 
 */
package org.algoristes.alkwarel.script;

/**
 * A single math operator, with a link to its children
 * 
 * @author Xavier Gouchet
 * 
 */
public class MathOperator extends MathNode {

	MathNode[] mChildren;

	/**
	 * Default constructor
	 * 
	 * @param value
	 */
	public MathOperator(String value) {
		super(value);
		mChildren = new MathNode[]{};
	}

	/**
	 * Sets the children of this operator
	 * 
	 * @param children
	 */
	public void setChildren(MathNode[] children) {
		mChildren = children;
	}

	/**
	 * @see MathNode#toString()
	 */
	public String toString() {
		if (mChildren == null)
			return mValue;

		String str = mValue + "(";
		for (MathNode n : mChildren) {
			str += n.toString() + ",";
		}
		str += ")";
		return str;
	}

	/**
	 * @see MathNode#eval()
	 */
	public double eval() {
		if (mValue.equals("*"))
			return evalMultiply();

		if (mValue.equals("/"))
			return evalDivide();

		if (mValue.equals("+"))
			return evalAdd();

		if (mValue.equals("-"))
			return evalSubtract();

		if (mValue.equals("%"))
			return evalModulo();

		if (mValue.equals("!"))
			return evalNot();

		if (mValue.equals(">"))
			return evalGreater();

		if (mValue.equals(">="))
			return evalGreaterEqual();

		if (mValue.equals("<"))
			return evalLess();

		if (mValue.equals("<="))
			return evalLessEqual();

		if (mValue.equals("=="))
			return evalEqual();

		if (mValue.equals("!="))
			return evalNotEqual();

		return 0;
	}

	/**
	 * Eval the node as a boolean negation
	 * 
	 * @return the result (0 or 1)
	 */
	public double evalNot() {
		if (mChildren.length != 2)
			throw new RuntimeException("Negation needs two operands");

		double b;
		b = mChildren[1].eval();

		return ((b == 0) ? 1 : 0);
	}

	/**
	 * Eval the node as a multiplication
	 * 
	 * @return the product (a * b);
	 */
	public double evalMultiply() {
		if (mChildren.length != 2)
			throw new RuntimeException("Multiplication needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return a * b;
	}

	/**
	 * Eval the node as a division
	 * 
	 * @return the quotient (a / b);
	 */
	public double evalDivide() {
		if (mChildren.length != 2)
			throw new RuntimeException("Division needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();
		if (b == 0)
			throw new RuntimeException("Division by 0 ! ");

		return a / b;
	}

	/**
	 * Eval the node as a addition
	 * 
	 * @return the sum (a + b);
	 */
	public double evalAdd() {
		if (mChildren.length != 2)
			throw new RuntimeException("Addition needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return a + b;
	}

	/**
	 * Eval the node as a subtraction. Also works as a unary operator (-1)
	 * 
	 * @return the difference (a - b);
	 */
	public double evalSubtract() {
		if (mChildren.length != 2)
			throw new RuntimeException("Subtraction needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return a - b;
	}

	/**
	 * Eval the node as a modulo
	 * 
	 * @return the rest (a % b);
	 */
	public double evalModulo() {
		if (mChildren.length != 2)
			throw new RuntimeException("Modulo needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();
		if (b == 0)
			throw new RuntimeException("Division by 0 ! ");

		return a % b;
	}

	/**
	 * Eval the node as a greater than comparison
	 * 
	 * @return the comparison (a > b);
	 */
	public double evalGreater() {
		if (mChildren.length != 2)
			throw new RuntimeException("Greater needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a > b) ? 1 : 0);
	}

	/**
	 * Eval the node as a greater or equal comparison
	 * 
	 * @return the comparison (a >= b);
	 */
	public double evalGreaterEqual() {
		if (mChildren.length != 2)
			throw new RuntimeException("Greater or Equal needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a >= b) ? 1 : 0);
	}

	/**
	 * Eval the node as a less than comparison
	 * 
	 * @return the comparison (a < b);
	 */
	public double evalLess() {
		if (mChildren.length != 2)
			throw new RuntimeException("Less needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a < b) ? 1 : 0);
	}

	/**
	 * Eval the node as a less or equal comparison
	 * 
	 * @return the comparison (a <= b);
	 */
	public double evalLessEqual() {
		if (mChildren.length != 2)
			throw new RuntimeException("Less or Equal needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a <= b) ? 1 : 0);
	}

	/**
	 * Eval the node as a not equal comparison
	 * 
	 * @return the comparison (a != b);
	 */
	public double evalNotEqual() {
		if (mChildren.length != 2)
			throw new RuntimeException("Inequality needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a != b) ? 1 : 0);
	}

	/**
	 * Eval the node as a equal comparison
	 * 
	 * @return the comparison (a == b);
	 */
	public double evalEqual() {
		if (mChildren.length != 2)
			throw new RuntimeException("Equality needs two operands");

		double a, b;
		a = mChildren[0].eval();
		b = mChildren[1].eval();

		return ((a == b) ? 1 : 0);
	}

}